package com.voice.call.filter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;

import com.voice.call.common.Const;
import com.voice.call.common.ConstLang;
import com.voice.call.common.Result;
import com.voice.call.common.ResultEnum;
import com.voice.call.exception.CommonException;
import com.voice.call.service.UserInfoService;
import com.voice.call.utils.JSONUtil;
import com.voice.call.utils.StringUtil;


public class AuthFilter implements Filter{
	
	private final Logger log = LoggerFactory.getLogger(AuthFilter.class);

	//白名单
	private static List<String> signWhiteList = Collections.synchronizedList(new ArrayList<String>());
	
	//不加密名单
	private static List<String> dncryptList = Collections.synchronizedList(new ArrayList<String>());
		
	private UserInfoService userInfoService;

	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
		 ServletContext sc = filterConfig.getServletContext(); 
	     XmlWebApplicationContext cxt = (XmlWebApplicationContext)WebApplicationContextUtils.getWebApplicationContext(sc);
	     userInfoService = cxt.getBean(UserInfoService.class);
	     //if(cxt != null && cxt.getBean("userInfoService") != null && userInfoService == null)
	    	 //userInfoService = (UserInfoService) cxt.getBean("userInfoService");  
		
		//sign签名 url白名单(跳过验证)
		signWhiteList.add("/user/autoLogin");//自动登录
		signWhiteList.add("/user/fbLogin");//fb登录
		signWhiteList.add("/user/accountLogin");//帐号+密码登录
		signWhiteList.add("/user/smsLogin");//手机+验证码登录
		signWhiteList.add("/user/query");//查询帐户信息
		signWhiteList.add("/sms/send");//短信发送
		signWhiteList.add("/config/list");//全局配置
		signWhiteList.add("/user/exists");//查询用户是否存在
		signWhiteList.add("/clear/cache/");//清除缓存
		
		signWhiteList.add("/user/update");//更新用户信息
		signWhiteList.add("/feedback/suggestion");//意见反馈
		signWhiteList.add("/sms/receive");//短信回调
		
		
		 
		
		dncryptList.add("/vos/create");//vos创建
		dncryptList.add("/vos/delete");//vos删除
		dncryptList.add("/vos/query");//vos查询
		
		dncryptList.add("/user/update");//更新用户信息
		dncryptList.add("/feedback/suggestion");//意见反馈
		dncryptList.add("/upload/file");//上传文件
		dncryptList.add("/sms/receive");//短信回调
		
		
		//资源文件
        String[] resourceArr = {".gif",".png",".jpg",".html",".ico",".css",".js",".txt"};
		
		signWhiteList.addAll(Arrays.asList(resourceArr));
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		//long start = System.currentTimeMillis();
		
		request.setCharacterEncoding(Const.UTF8); //配置信息
		
		if (request instanceof HttpServletRequest) {
			String url = ((HttpServletRequest) request).getRequestURI();
			
			if (isDncryptWhiteList(url)) { //不需要解密
				log.info("请求url:{}",url);
				//log.info("不需要解密");
				//不用做解密处理
				chain.doFilter(request, response);//放行
				
			}else { //解密处理
				
				HttpServletRequest requestWrapper = new LocalHttpServletRequestWrapper((HttpServletRequest) request);
				if (!isSignWhiteList(url)) { //不是白名单
					//获取请求body
	           	    String body = this.getBody(requestWrapper);
	                try {
	                	
		                 //打印输出
	                	 writeLog(url,requestWrapper.getMethod(),getRequestHeader(requestWrapper),body);
		                 
	                	 if(!url.contains("version/update")) { // 非版本更新，进行验证
	                		 //验证sign
			        	     validSign(requestWrapper,body);
	                	 }else {
	                		 //log.info("版本更新请求version");
	                	 }
	                	
		                
	                }catch (Exception e) {
						handleException((HttpServletResponse)response,e);
						log.error("doFilter exception:",e);
						return;
					}
	                
	                //chain.doFilter(request, response);
	                chain.doFilter(requestWrapper, response); 
				}else{
					chain.doFilter(requestWrapper, response);//放行
				}
				//long end = System.currentTimeMillis();
	        	//log.info("{}耗时{}毫秒",url,end-start);
			}
			
			
		}else {
			chain.doFilter(request, response);//放行
		}
	}
	
	@Override
	public void destroy() {

	}
	
	
	
	/**
	 * sign 验证
	 * @param requestWrapper
	 * @param response
	 * @param chain
	 * @return
	 * @throws IOException
	 */
	private void validSign(HttpServletRequest requestWrapper,String body) {
		
		String uid = requestWrapper.getParameter("uid"),token = requestWrapper.getParameter("token");
		String v = requestWrapper.getParameter("v"); //判断版本是否存在
		String lang = requestWrapper.getParameter("lang"); //语言
		if (StringUtil.isEmpty(lang)) {
			lang = Const.LANGUAGE;
		}
		
		if (StringUtil.isEmpty(uid) || StringUtil.isEmpty(token)) {
			
			if(!StringUtil.isEmpty(body)){ //如果body不为空
	    		
	    		Map<String, Object> jsonMap =JSONUtil.jsonToMap(body);
	    		if(jsonMap!=null&&jsonMap.get("uid")!=null){
	    			uid = jsonMap.get("uid").toString();
	    		}
	    		if(jsonMap!=null&&jsonMap.get("token")!=null){
	    			token = jsonMap.get("token").toString();
	    		}
	    		if(jsonMap!=null&&jsonMap.get("v")!=null){
	    			v = jsonMap.get("v").toString();
	    		}
	    		lang = ConstLang.getLang(jsonMap);
	    	}
		}

        if (StringUtil.isEmpty(v) || StringUtil.isEmpty(uid) || StringUtil.isEmpty(token) || (!StringUtil.isEmpty(uid) && !StringUtil.isInteger(uid))) {
        	
        	throw new CommonException(ResultEnum.PARAM_ERROR,lang);
		}
        
        //判断是不是低版本
        v = v.replaceAll("[^0-9]+", "");
        if(StringUtil.isInteger(v)){
        	//log.info("版本为数字");
        	int version = Integer.valueOf(v).intValue();
    		if(version < 101101){
    			//log.info("版本小于1101提示版本更新!!!");
    			throw new CommonException(ResultEnum.DOWNLOAD_VERSION,lang);
    		}
        }else {
        	//log.error("版本为非数字，v={}",v);
		}
        ResultEnum rsVerify = userInfoService.requestVerify(uid, token);
        if (rsVerify!=null) {
        	throw new CommonException(rsVerify,lang);
		}
		
	}
	
	
	//判断是否需要解密
	private boolean isDncryptWhiteList(String url) {
		for (String u : dncryptList) {
			if (url.indexOf(u) != -1) {
				return true;
			}
		}
        return false;
	}
	
	 //判断是否sign签白名单
    private boolean isSignWhiteList(String url) {
		for (String u : signWhiteList) {
			if (url.indexOf(u) != -1) {
				return true;
			}
		}
        return false;
    }
    
    //获取请求body
    private String getBody(HttpServletRequest request) throws IOException {
		BufferedReader br = null;
		String body = null;
		try {
			br = request.getReader();
			StringBuffer buff = new StringBuffer();
			while ((body = br.readLine()) != null) {
				buff.append(body);
			}
			body = buff.toString().trim();
			br.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return body;
	}
    
    private void handleException(HttpServletResponse response,Exception e){
		Result result = new Result(ResultEnum.SYSTEM_ERROR);
		if (e instanceof CommonException) {
			CommonException ex = (CommonException) e;
			result.setCode(ex.getCode());
			result.setMsg(ex.getMessage());
		}
    	this.responseOutWithJson(response,result);
    }
	
	/**
     * 返回json
     * @param response
     * @param responseObject
     */
    private void responseOutWithJson(HttpServletResponse response,
			Object responseObject) {
		//将实体对象转换为JSON Object转换
		String jsonStr = JSONUtil.objectToJson(responseObject);
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json; charset=utf-8");
		PrintWriter out = null;
		try {
			out = response.getWriter();
			out.append(jsonStr);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}
    
    /**
	 * 流量控制
	 * @param requestWrapper
	 * @param response
	 * @param chain
	 * @throws ServletException 
	 * @throws IOException 
	 */
	private void writeLog(String url,String method,String headers,String body) throws IOException, ServletException{
		
		StringBuilder sBuilder = new StringBuilder();
		sBuilder.append("请求url:"+url+"\n");
		sBuilder.append("请求头信息:"+headers+"\n");
		sBuilder.append("请求body:"+body+"\n");
		log.info(sBuilder.toString());
		//log.info("请求参数:{}",body);
		
	}
	
	private String getRequestHeader(HttpServletRequest request){
		Enumeration<String> enu = request.getHeaderNames();
		Map<String, String> map = new HashMap<String, String>();
		while (enu.hasMoreElements()) {
			String headerName = enu.nextElement();
			String headerValue = request.getHeader(headerName);// 取出头信息内容
			map.put(headerName, headerValue);
		}
		return JSONUtil.objectToJson(map);
	}
}
